#include "ShaderLoader.h"
#include "ResourceManager.h"
#include "Renderer.h"
#include <fstream>
#include <cstring>

using namespace std;

namespace glow {

ShaderLoader::ShaderLoader()
{
}

ShaderLoader::~ShaderLoader()
{
}

ShaderBase *ShaderLoader::load(const string &filename)
{
	Renderer *rdr = Renderer::getInstance();
	if(rdr->checkExtension("GL_ARB_shading_language_100") &&
		rdr->checkExtension("GL_ARB_shader_objects") &&
		rdr->checkExtension("GL_ARB_vertex_shader") &&
		rdr->checkExtension("GL_ARB_fragment_shader"))
    {
		ResourceManager *rsmgr = ResourceManager::getInstance();
		ShaderBase *shaderBase = rsmgr->get<ShaderBase>(filename);
		if(!shaderBase)
		{
			GLuint shader;
			string extension = "";
			bool find = false;
			int size = filename.size();

			for(int i=size-1; i>0 && !find; i--)
			{
				if(filename[i] == '.') find = true;
				else extension = filename[i] + extension;
			}

			if(extension == "vert")
			{
				shader = loadShader(GL_VERTEX_SHADER, filename.c_str());
				shaderBase = new ShaderBase(GL_VERTEX_SHADER, shader, filename.c_str());
			}
			else if(extension == "frag")
			{
				shader = loadShader(GL_FRAGMENT_SHADER, filename.c_str());
				shaderBase = new ShaderBase(GL_FRAGMENT_SHADER, shader, filename.c_str());
			}
			else
				cout << "Wrong shader extension : " << extension << endl;
		}
		return shaderBase;
    }
  else
    {
      cout << "Couln't create shader : " << filename << " Shaders not supported"  << "\n";
      return NULL;
    }
}

char *ShaderLoader::loadSource(const char *filename)
{
    char *src = NULL;
    long size = 0, i = 0;

    ifstream file(filename, ios::in | ios::binary);
    if(file)
    {
        file.seekg(0, std::ios_base::end);

        size = file.tellg();

        file.seekg(0, std::ios_base::beg);

        src = new char[size+1];

        while(!file.eof())
        {
            file.get(src[i]);
            i++;
        }

        src[size] = '\0';

        file.close();
    }
    else
        cout << "Couldn't load shader " << filename << endl;

    return src;
}

GLuint ShaderLoader::loadShader(GLenum type, const char *filename)
{
    GLuint shader = 0;
    GLsizei logsize = 0;
    GLint compile_status = GL_TRUE;
    char *src = NULL, *log = NULL;

    shader = glCreateShaderObjectARB(type);
    if(shader == 0)
    {
        cout << "Couln't create shader" << "\n";
        return 0;
    }

    src = loadSource(filename);
    if(!src)
    {
        glDeleteObjectARB(shader);
        return 0;
    }

    glShaderSourceARB(shader, 1, (const GLchar**)&src, NULL);

    glCompileShaderARB(shader);

    glGetObjectParameterivARB(shader, GL_COMPILE_STATUS, &compile_status);
    if(compile_status != GL_TRUE)
    {
        glGetObjectParameterivARB(shader, GL_INFO_LOG_LENGTH, &logsize);

        log = new char[logsize + 1];
        if(log == NULL)
        {
            cout << "Couldn't create shader" << "\n";
            return 0;
        }

        memset(log, '\0', logsize + 1);

        glGetInfoLogARB(shader, logsize, &logsize, log);

        cout << "Couldn't compile shader " << filename << ":\n" << log << "\n";

        delete[] log;
        glDeleteObjectARB(shader);

        return 0;
    }
    return shader;
}

}
